'''
Created on Feb 27, 2012

@author: lino possamai - www.possamai.it/lino
@license: GPLv3
'''

import efficiency
import random, time, os, sys
from rules import get_rule_name
from rules import sel_group_in_probability
from rules import select_edge
from rules import aristocratic_original
from rules import init_aristocratic
from rules import preferential

from utility import load_pickled_data
from random import shuffle
import networkx as nx

def evolution_accelerated(aggiustamento,filename, tecnica, id_run, file_archi, file_graph, cores):
    
    a=1;     k=1;    u=[];     v=[];
    
    narchiAggiunti=0
    descrittori={}

    archi=load_pickled_data(file_archi)
    g_complete=load_pickled_data(file_graph)
        
    nnodi  = len(g_complete.nodes())
    narchi = len(archi)
    print nnodi, narchi
    
    if tecnica!=2:
        shuffle(archi)
        descrittori[1]=set(archi)
        g=nx.Graph()
        g.add_nodes_from(range(1,nnodi+1))
    else:
        descrittori, GO, GO_incr = init_aristocratic(g_complete,nnodi)   
    
    fh=open("acc_%s_%.1f_%d.txt" % (get_rule_name(tecnica),float(aggiustamento),id_run),"w")
    
    nome = filename.split("/")[-1].split(".")[0].lower()
    
    while ((a>0) and (narchi!=narchiAggiunti)):
        
        lista_edges=[]
        u=[]
        v=[]
        print "k=%d (%d)\n" % ( k, narchi-narchiAggiunti)
                
        for i in range(0, a):
            if narchiAggiunti==narchi:
                break
            narchiAggiunti+=1
            
            index = sel_group_in_probability(descrittori)

            if tecnica!=2:
                e = select_edge(index, descrittori, tecnica, g, g_complete)
            else: 
                e = aristocratic_original(index,descrittori,GO_incr,GO,g_complete)
                
            lista_edges.append(e)
            if i % 100 == 0:
                print i
        
            
        [u.append(e[0]) for e in lista_edges]
        [v.append(e[1]) for e in lista_edges]
        
            
        #print "ppp",len(u),len(v)
        t=time.time()
        b=efficiency.eglob_unweighted(nome,cores,u,v,nnodi, narchi, get_rule_name(tecnica))
        print time.time()-t
        
        #fh.write("%d %f\n" % (k,b))
        fh.write("%d %d %f\n" % (k,a,b))
        if k % 10 ==0:
            fh.flush()
            
        k+=1
        a=int((aggiustamento*float(narchi-narchiAggiunti-1)*b)+1.0)

        print "narchi=%d narchiAggiunti=%d b=%f a=%d\n" % (narchi, narchiAggiunti, b,a)
    
    remove_files(get_rule_name(tecnica),nome)

    fh.close()

def remove_files(rule_name, nome, nsir=0):
    
    if nsir==0:
        #nessuna sirena -------------------------
        try:    
            os.remove("%s%s_va.bin" % (rule_name,nome))            
        except:
            try:
                os.remove("/tmp/%s%s_va.bin" % (rule_name,nome))
            except:
                pass
        try:
            os.remove("%s%s_ea.bin" % (rule_name,nome))
        except:
            try:
                os.remove("/tmp/%s%s_ea.bin" % (rule_name,nome))
            except:
                pass
        
        try:
            os.remove("%s%s_go.bin" % (rule_name,nome))
        except:
            try:
                os.remove("/tmp/%s%s_go.bin" % (rule_name,nome))
            except:
                pass
    else:
        #sirene ---------------------------------------------------
        try:
            os.remove("%s%s_va_%d.bin" % (rule_name,nome,nsir))
        except:
            try:
                os.remove("/tmp/%s%s_va_%d.bin" % (rule_name,nome,nsir))
            except:
                pass
        
        try:
            os.remove("%s%s_ea_%d.bin" % (rule_name,nome,nsir))
        except:
            try:
                os.remove("/tmp/%s%s_ea_%d.bin" % (rule_name,nome,nsir))
            except:
                pass
        try:
            os.remove("%s%s_go_%d.bin" % (rule_name,nome,nsir))
        except:
            try:
                os.remove("/tmp/%s%s_go_%d.bin" % (rule_name,nome,nsir))
            except:
                pass


def evolution_accelerated_sirens_broadcast(aggiustamento,filename, tecnica, id_run,nsir, attrattivita,durataSirene,file_archi, file_graph,cores):
    
    descrittori={}
    
    u=[];     v=[];     u_s=[];    v_s=[];
    
    narchiAggiunti=0
    
    nome = filename.split("/")[-1].split(".")[0].lower()
    
    archi=load_pickled_data(file_archi)
    g_complete=load_pickled_data(file_graph)
    
    nnodi=len(g_complete.nodes())
    narchi=len(archi)
    
    shuffle(archi)
    
    if tecnica!=2:
        descrittori[1]=set(archi)
        g=nx.Graph()
        g.add_nodes_from(range(1,nnodi+1))
    else:
        descrittori, GO, GO_incr = init_aristocratic(g_complete,nnodi)
    
    #sirene
    archi_sir=[(r,n) for r in range(nnodi+1, nnodi+nsir+1) for n in range(1,nnodi+1)]
    lista_archi_sir={}
    
    shuffle(archi_sir)
    lista_archi_sir[1]=set(archi_sir)
    
    fh=open("acc_%s_gps_bro_%d_%.4f_%.1f_%d_%d.txt" % (get_rule_name(tecnica),nsir, attrattivita, aggiustamento,durataSirene, id_run),"w")
    
    a=1;     k=1;
    
    narchisir=nsir*nnodi
    s=int(attrattivita*float(narchisir))
    print "s=%d" % (s,)
    
    narchiSirAdded=0;
    
    while ((a>0) and (narchi!=narchiAggiunti)):
        
        lista_edges=[]
        u=[];  v=[]; u_s=[]; v_s=[] 
        
        for i in range(0, a):       #inserisco gli archi normali
            if narchiAggiunti==narchi:
                break
            narchiAggiunti+=1
            
            index = sel_group_in_probability(descrittori)
            if tecnica!=2:
                e = select_edge(index, descrittori, tecnica, g,g_complete)
            else:
                e = aristocratic_original(index,descrittori,GO_incr,GO,g_complete)
                
            lista_edges.append(e)

            
        [u.append(e[0]) for e in lista_edges]
        [v.append(e[1]) for e in lista_edges]
        
        [u_s.append(e[0]) for e in lista_edges]
        [v_s.append(e[1]) for e in lista_edges]
        
        #inserisco gli archi sirena-nodi normali
        if k<durataSirene:
            if s!=0 and narchisir!=narchiSirAdded:
                lista_edges=[]
                for i in range(0, s):
                    if narchiSirAdded==narchisir:
                        break
                    narchiSirAdded+=1
                    
                    index = 1
                    e=select_edge(index, lista_archi_sir, 1,None)	#1=random technique (so broadcast model)
                    lista_edges.append(e)
                
                [u_s.append(e[0]) for e in lista_edges]
                [v_s.append(e[1]) for e in lista_edges]
            
        bn = efficiency.eglob_unweighted(nome,cores,u,v, nnodi, narchi, get_rule_name(tecnica))
        b  = efficiency.eglob_unweighted_sir(nome,cores,nsir,u_s,v_s,nnodi, narchi, get_rule_name(tecnica))
        

        fh.write("%d %f\n" % (k,bn))
        if k % 10 ==0:
            fh.flush()
            
        k+=1
        a=int((aggiustamento*float(narchi-narchiAggiunti-1)*b)+1.0)
        print "k=%d nn %d ns %d g+s %f g %f\n" % (k,narchi-narchiAggiunti, narchisir-narchiSirAdded,b,bn)
        print "a=%d" % (a,)

    remove_files(get_rule_name(tecnica),nome)
    remove_files(get_rule_name(tecnica),nome, nsir)
#    os.remove("%s%s_va.bin" % (get_rule_name(tecnica),nome))
#    os.remove("%s%s_ea.bin" % (get_rule_name(tecnica),nome))
#    os.remove("%s%s_go.bin" % (get_rule_name(tecnica),nome))
#    os.remove("%s%s_va_%d.bin" % (get_rule_name(tecnica),nome,nsir))
#    os.remove("%s%s_ea_%d.bin" % (get_rule_name(tecnica),nome,nsir))
#    os.remove("%s%s_go_%d.bin" % (get_rule_name(tecnica),nome,nsir))
    fh.close()

def create_graph(nodi):
    #creates a graph with n nodes (no edges)
    g=nx.Graph()
    g.add_nodes_from(nodi)
    return g

def delete_present_edges(lista_edges_soc, gs):
    # elimina dalla lista di edges passata come parametro gli archi che sono gia' presenti nella rete gs
    l=set()
    for k in lista_edges_soc:
        if not gs.has_edge(k[0],k[1]):
            l.update([k])
            
    return l

def shift_descrittori_pass(lista_edges,descrittori):
    #sposta gli archi passati come lista_edges nei descrittori a probabilita' superiore
    for a in lista_edges:
        for k in descrittori.keys(): 
            if (a[0],a[1]) in descrittori[k]: 
                descrittori[k].remove(a)
                descrittori.setdefault(k+1,set())
                descrittori[k+1].update([a])
                break
            if (a[1],a[0]) in descrittori[k]:
                descrittori[k].remove((a[1],a[0]))
                descrittori.setdefault(k+1,set())
                descrittori[k+1].update([(a[1],a[0])])
                break

def gestione_wordofmouth(gn,gs,nnodi,e,tipo,descrittori):
    
    if tipo==1:     #edge da sirena a nodi normali
        if e[0]<= nnodi:
            u=e[0]
            s=e[1]
        else:
            u=e[1]
            s=e[0]
        n=gn.neighbors(u)       #lista vicini di u nella rete normale
        lista_edges_soc = set([(s,b) for b in n])
    
    if tipo==2:     #edge da nodi normali a nodi normali
        
        u=e[0]; v=e[1]
        
        n1 = gs.neighbors(u)
        n2 = gs.neighbors(v)
        
        n1 = [e for e in n1 if e > nnodi]
        n2 = [e for e in n2 if e > nnodi]
        
        lista_edges_soc = set([(v,b) for b in n1])
        l2 = [(u,b) for b in n2]
        lista_edges_soc.update(l2)
            
    lista_edges_soc = delete_present_edges(lista_edges_soc, gs)
    
    shift_descrittori_pass(lista_edges_soc, descrittori)
        

def evolution_accelerated_sirens_wordofmouth(aggiustamento,filename, tecnica, id_run,nsir, attrattivita,durataSirene,file_archi, file_graph,cores):
    
    descrittori={}
    
    u=[];     v=[];     u_s=[];    v_s=[];
    
    narchiAggiunti=0    
    
    nome = filename.split("/")[-1].split(".")[0].lower()
    
    archi=load_pickled_data(file_archi)
    g_complete=load_pickled_data(file_graph)
    
    nnodi=len(g_complete.nodes())
    narchi=len(archi)
    
    gn=create_graph(range(1,nnodi+1))
    gs=create_graph(range(1,nnodi+nsir+1))
    
    shuffle(archi)
    
    if tecnica!=2:
        descrittori[1]=set(archi)
        g=gn.copy()
    else:
        descrittori, GO, GO_incr = init_aristocratic(g_complete,nnodi)
    
    #sirene
    archi_sir=[(r,n) for r in range(nnodi+1, nnodi+nsir+1) for n in range(1,nnodi+1)]
    descrittori_sir={}
    shuffle(archi_sir)
    descrittori_sir[1]=set(archi_sir)
    
    fh=open("acc_%s_gps_passa_%d_%.4f_%.1f_%d_%d.txt" % (get_rule_name(tecnica),nsir, attrattivita, aggiustamento,durataSirene, id_run),"w")
    
    a=1;     k=1;
    
    narchisir=nsir*nnodi
    s=int(attrattivita*float(narchisir))
    print "s=%d" % (s,)
    
    narchiSirAdded=0;
    
    while ((a>0) and (narchi!=narchiAggiunti)):
        
        lista_edges=[]; u=[]; v=[]; u_s=[]; v_s=[]
        
        for i in range(0, a):       #inserisco gli archi normali
            if narchiAggiunti==narchi:
                break
            narchiAggiunti+=1
            
            index = sel_group_in_probability(descrittori)
            if tecnica!=2:
                e = select_edge(index, descrittori, tecnica, g,g_complete)
            else:
                e = aristocratic_original(index,descrittori,GO_incr,GO,g_complete)
                
            lista_edges.append(e)
            if k<durataSirene:
                gn.add_edge(e[0], e[1])
                gs.add_edge(e[0], e[1])
                gestione_wordofmouth(gn,gs,nnodi,e,2, descrittori_sir)

            
        [u.append(e[0]) for e in lista_edges]
        [v.append(e[1]) for e in lista_edges]
        
        [u_s.append(e[0]) for e in lista_edges]
        [v_s.append(e[1]) for e in lista_edges]
        
        
        #inserisco gli archi sirena-nodi normali
        if k<durataSirene:
            if s!=0 and narchisir!=narchiSirAdded:
                lista_edges=[]
                for i in range(0, s):
                    if narchiSirAdded==narchisir:
                        break
                    narchiSirAdded+=1
                    
                    index = sel_group_in_probability(descrittori_sir)
                    e=random.sample(descrittori_sir[index],1)[0]
                    lista_edges.append(e)
                    gs.add_edge(e[0], e[1])
                    gestione_wordofmouth(gn,gs,nnodi,e,1,descrittori_sir)
                    
                [u_s.append(e[0]) for e in lista_edges]
                [v_s.append(e[1]) for e in lista_edges]
            
        
        bn = efficiency.eglob_unweighted(nome,cores,u,v, nnodi, narchi, get_rule_name(tecnica))
        b  = efficiency.eglob_unweighted_sir(nome,cores,nsir,u_s,v_s, nnodi, narchi, get_rule_name(tecnica))
        

        fh.write("%d %f\n" % (k,bn))
        if k % 10 ==0:
            fh.flush()
            
        k+=1
        a=int((aggiustamento*float(narchi-narchiAggiunti-1)*b)+1.0)
        print "k=%d nn %d ns %d g+s %f g %f\n" % (k,narchi-narchiAggiunti, narchisir-narchiSirAdded,b,bn)
        print "a=%d" % (a,)

    remove_files(get_rule_name(tecnica),nome)
    remove_files(get_rule_name(tecnica),nome,nsir)
#    os.remove("%s%s_va.bin" % (get_rule_name(tecnica),nome))
#    os.remove("%s%s_ea.bin" % (get_rule_name(tecnica),nome))
#    os.remove("%s%s_go.bin" % (get_rule_name(tecnica),nome))
#    os.remove("%s%s_va_%d.bin" % (get_rule_name(tecnica),nome,nsir))
#    os.remove("%s%s_ea_%d.bin" % (get_rule_name(tecnica),nome,nsir))
#    os.remove("%s%s_go_%d.bin" % (get_rule_name(tecnica),nome,nsir))
    fh.close()

def create_gs_complete_graph(nnodi, nsir):
	#creates a graph that has all edges between sirens and normal nodes
	gs_complete=create_graph(range(1,nnodi+nsir+1))
	
	for e1 in range(nnodi+1,nnodi+nsir+1):
		for e2 in range(1, nnodi+1):
			gs_complete.add_edge(e1,e2)
	
	return gs_complete

def evolution_accelerated_sirens_preferential(aggiustamento,filename, tecnica, id_run,nsir, attrattivita,durataSirene,file_archi, file_graph,cores):
    
    descrittori={}		#normal network descriptor 
    
    u=[];     v=[];     u_s=[];    v_s=[];
    
    narchiAggiunti=0    
    
    nome = filename.split("/")[-1].split(".")[0].lower()
    
    archi	= load_pickled_data(file_archi)
    g_complete	= load_pickled_data(file_graph)
    
    
    
    nnodi=len(g_complete.nodes())
    narchi=len(archi)
    
    gn		= create_graph(range(1,nnodi+1))
    gs 		= create_graph(range(1,nnodi+nsir+1))
    gs_complete	= create_gs_complete_graph(nnodi,nsir)
    GO_sir_incr	= [0]*(nnodi+nsir+1)
    
    shuffle(archi)
    
    if tecnica!=2:
        descrittori[1]=set(archi)
        g=gn.copy()
    else:
        descrittori, GO, GO_incr = init_aristocratic(g_complete,nnodi)
    
    #the key of the "descrittori_sir" dictionary represents the degree of the siren + 1
    descrittori_sir = {}
    descrittori_sir = dict(tuple(zip(range(2,nnodi+1),[set() for i in range(2,nnodi+1)])))
    descrittori_sir[1]=set(range(nnodi+1,nnodi+1+nsir))     					#at the beginning, all the sirens will have degree 1
    
    fh=open("acc_%s_gps_pref_%d_%.4f_%.1f_%d_%d.txt" % (get_rule_name(tecnica),nsir, attrattivita, aggiustamento,durataSirene, id_run),"w")
    
    a=1;     k=1;
    
    narchisir=nsir*nnodi
    s=int(attrattivita*float(narchisir))
    print "s=%d" % (s,)
    
    narchiSirAdded=0;
    
    while ((a>0) and (narchi!=narchiAggiunti)):

        lista_edges=[]; u=[]; v=[]; u_s=[]; v_s=[]
        
        for i in range(0, a):       #inserisco gli archi normali
            if narchiAggiunti==narchi:
                break
            narchiAggiunti+=1
            
            index = sel_group_in_probability(descrittori)
            if tecnica!=2:
                e = select_edge(index, descrittori, tecnica, g,g_complete)
            else:
                e = aristocratic_original(index,descrittori,GO_incr,GO,g_complete)
                
            lista_edges.append(e)

            
        [u.append(e[0]) for e in lista_edges]
        [v.append(e[1]) for e in lista_edges]
        
        [u_s.append(e[0]) for e in lista_edges]
        [v_s.append(e[1]) for e in lista_edges]
        
        
        #inserisco gli archi sirena-nodi normali
        if k<durataSirene:
            if s!=0 and narchisir!=narchiSirAdded:
                lista_edges=[]
                for i in range(0, s):
                    if narchiSirAdded==narchisir:
                        break
                    narchiSirAdded+=1
                    
                    index = sel_group_in_probability(descrittori_sir)
                    e = preferential(index,descrittori_sir,GO_sir_incr,gs_complete,nnodi)
                    lista_edges.append(e)
                    gs.add_edge(e[0], e[1])
                    
                [u_s.append(e[0]) for e in lista_edges]
                [v_s.append(e[1]) for e in lista_edges]
            
        
        bn = efficiency.eglob_unweighted(nome,cores,u,v, nnodi, narchi, get_rule_name(tecnica))
        b  = efficiency.eglob_unweighted_sir(nome,cores,nsir,u_s,v_s, nnodi, narchi, get_rule_name(tecnica))
        

        fh.write("%d %f\n" % (k,bn))
        if k % 10 ==0:
            fh.flush()
            
        k+=1
        a=int((aggiustamento*float(narchi-narchiAggiunti-1)*b)+1.0)
        print "k=%d nn %d ns %d g+s %f g %f\n" % (k,narchi-narchiAggiunti, narchisir-narchiSirAdded,b,bn)
        print "a=%d" % (a,)

    remove_files(get_rule_name(tecnica),nome)
    remove_files(get_rule_name(tecnica),nome,nsir)

    fh.close()
